﻿
using Newtonsoft.Json;
using ServiceStack.Caching;
using ServiceStack.Redis;
using ServiceStack.Redis.Generic;
using ServiceStack.Text;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;

namespace Yoze.Redis.Common
{
    public partial class RedisService : IDisposable
    {
        static PooledRedisClientManager clientManager;
        public RedisService(string url)
        {
            clientManager = PoolManagerFactory.CreateManager(
                                                    new string[] { url },
                                                    new string[] { url }
                                                    );

        }

        //public virtual IRedisClient Redis { get; set; } = clientManager.GetClient(); //= new RedisClient();
        /// <summary>
        /// 默认 时效
        /// </summary>
        private static TimeSpan TimeSpanDefault = TimeSpan.FromDays(1);

        public RedisService()
        {
        }

        /// <summary>
        /// 获取随机KEY
        /// </summary>
        /// <returns></returns>
        public string GetRandomKey()
        {
            using (var redis = clientManager.GetClient())
            {
                CREATE_RANDOM_KEY:
                string key = Guid.NewGuid().ToString().Replace("-", "");
                if (redis.ContainsKey(key)) goto CREATE_RANDOM_KEY;
                return key;
            }
        }

        public IRedisClient GetClient()
        {
            return clientManager.GetClient();
        }

        #region 普通缓存 存取
        /// <summary>
        /// 给指定 Key 对象更新过期时间
        /// </summary>
        /// <param name="key"></param>
        /// <param name="timeSpan"></param>
        public void ExpireEntryIn(string key, TimeSpan? timeSpan = null)
        {
            //Redis.ExpireEntryIn(key, timeSpan ?? TimeSpanDefault);
        }

        public void AddItem<T>(RedisGroup group, string key, T t, TimeSpan? timeSpan = null)
        {
            AddItem($"{group}:{key}", t, timeSpan);
        }

        /// <summary>
        /// 添加 对象到 缓存, 如不设时间, 自动设有效时间为 1天
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="t"></param>
        /// <param name="timeSpan"></param>
        public void AddItem<T>(string key, T t, TimeSpan? timeSpan = null)
        {
            //client.Add(key, t, timeSpan);
            using (var redis = clientManager.GetClient())
            {
                redis.Add(key, t, timeSpan ?? TimeSpanDefault);
            }
            Debug.WriteLine($"向redis缓存 key:{key} value:{t} timeSpan:{timeSpan}");
        }

        public T GetItem<T>(string key)
        {
            using (var redis = clientManager.GetClient())
            {
                return redis.Get<T>(key);
            }
        }
        public T GetItem<T>(RedisGroup group, string key)
        {
            return GetItem<T>($"{group}:{key}");
        }
        /// <summary>
        /// 移除指定 Key对象
        /// </summary>
        /// <param name="key"></param>
        public void Remove(string key)
        {

            using (var redis = clientManager.GetClient())
            {
                var value = redis.Get<object>(key);
                redis.Remove(key);
            }
            Debug.WriteLine($"从redis缓存清除数据 key:{key}");
        }
        public void Remove(RedisGroup group, string key)
        {
            Remove($"{group}:{key}");
        }

        public void Change(RedisGroup group, string key)
        {

        }
        #endregion

        #region Store
        /// <summary>
        /// 获取指定类型store
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IRedisTypedClient<T> GetStore<T>() where T : class
        {
            return clientManager.GetClient().As<T>();
        }

        /// <summary>
        /// 根据ID获取指定对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public T FindStore<T>(object id) where T : class
        {
            T entity = null;
            using (var redis = clientManager.GetClient())
            {
                entity = redis.As<T>().GetById(id);
            }
            return entity;
        }

        /// <summary>
        /// 获取指定类型store中所有对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IList<T> GetAllByStore<T>() where T : class
        {
            using (var redis = clientManager.GetClient())
            {
                return redis.As<T>().GetAll();
            }
        }

        public bool ContainsKeyStore<T>(object id) where T : class
        {
            using (var redis = clientManager.GetClient())
            {
                return redis.As<T>().GetAllKeys().Contains(id);
            }
        }

        public T AddStore<T>(T model, TimeSpan? time = null) where T : class
        {
            T entity = null;
            using (var redis = clientManager.GetClient())
            {
                if (time == null)
                    entity = redis.As<T>().Store(model);
                else
                    entity = redis.As<T>().Store(model, time.Value);
            }
            return entity;
        }

        public void RemoveStore<T>(T model) where T : class
        {
            using (var redis = clientManager.GetClient())
            {
                redis.As<T>().Delete(model);
            }
        }

        public void FlushStore<T>() where T : class
        {
            using (var redis = clientManager.GetClient())
            {
                redis.As<T>().DeleteAll();
            }
        }
        public void AddItemToList(string listId, string listValue)
        {
            using (var redis = clientManager.GetClient())
            {
                redis.AddItemToList(listId, listValue);
            }
        }

        public List<string> GetList(string listId)
        {
            using (var redis = clientManager.GetClient())
            {
                return redis.GetAllItemsFromList(listId);
            }
        }

        public void AddQequeue(string listId, string listValue)
        {
            using (var redis = clientManager.GetClient())
            {
                redis.EnqueueItemOnList(listId, listValue);
            }
        }

        public string GetQequeue(string listId)
        {
            using (var redis = clientManager.GetClient())
            {
                return redis.DequeueItemFromList(listId);
            }
        }
        public long GetListCount(string listId)
        {
            using (var redis = clientManager.GetClient())
            {
                return redis.GetListCount(listId);
            }
        }
        #endregion

        public async Task Subscription(string channelName, Action<string, string> onRevice)
        {
            var sub = GetClient().CreateSubscription();
            sub.OnMessage = onRevice;
            await Task.Run(() =>
            {
                sub.SubscribeToChannels(channelName);
            });
        }

        public void PublishMessage(string channelName, string msg)
        {
            GetClient().PublishMessage(channelName, msg);
        }

        public void Clear()
        {
            using (var redis = clientManager.GetClient())
            {

            }
        }

        public bool IsCached(string key)
        {
            return false;//Redis.ContainsKey(key);
            //return client.ContainsKey(key);
        }

        ///// <summary>
        ///// 加入队列(先进先出)
        ///// </summary>
        ///// <param name="key"></param>
        ///// <param name="value"></param>
        //public void EnqueueItem(string key, string value)
        //{
        //    client.EnqueueItemOnList(key, value);
        //}
        ///// <summary>
        ///// 从队列中取数据(先进先出)
        ///// </summary>
        ///// <param name="key"></param>
        ///// <returns></returns>
        //public string DequeueItem(string key)
        //{
        //    return client.DequeueItemFromList(key);
        //}
        ///// <summary>
        ///// 加入盏(先进后出)
        ///// </summary>
        ///// <param name="key"></param>
        ///// <param name="value"></param>
        //public void PushItem(string key, string value)
        //{
        //    client.EnqueueItemOnList(key, value);
        //}
        ///// <summary>
        ///// 从盏中取数据(先进后出)
        ///// </summary>
        ///// <param name="key"></param>
        ///// <returns></returns>
        //public string PopItem(string key)
        //{
        //    return client.DequeueItemFromList(key);
        //}
        public void Log(RedisLogStatus status, string msg)
        {
            //Redis.Add($"RunTimeLog:{status}:{DateTime.Now.ToString("yyyyMMdd:HHmmss_")}{Math.Floor(DateTime.Now.ToUTCDateTime())}", msg);
        }
        public void Dispose()
        {
            //Redis.Dispose();
        }
    }

    /// <summary>
    /// redis 分组
    /// </summary>
    public enum RedisGroup
    {
        /// <summary>
        /// 移动端 用户登录信息
        /// </summary>
        API_User_Login_Token,
        /// <summary>
        /// 移动API帮助文档
        /// </summary>
        API_Help_Session_Token,
        /// <summary>
        /// 短信
        /// </summary>
        SMS,
        /// <summary>
        /// 地理位置
        /// </summary>
        GEO
    }

    public enum RedisLogStatus
    {
        Error,
        Info,
        Debug
    }

}
